package com.guli.acl.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.guli.acl.entity.Permission;
import com.guli.acl.entity.Role;
import com.guli.acl.entity.RolePermission;
import com.guli.acl.entity.User;
import com.guli.acl.helper.MemuHelper;
import com.guli.acl.helper.PermissionHelper;
import com.guli.acl.mapper.PermissionMapper;
import com.guli.acl.service.PermissionService;
import com.guli.acl.service.RolePermissionService;
import com.guli.acl.service.UserService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 权限 服务实现类
 * </p>
 *
 * @author testjava
 * @since 2020-01-12
 */
@Service
public class PermissionServiceImpl extends ServiceImpl<PermissionMapper, Permission> implements PermissionService {

    @Autowired
    private RolePermissionService rolePermissionService;
    
    @Autowired
    private UserService userService;
    
    //获取全部菜单
    @Override
    public List<Permission> queryAllMenu() {

        QueryWrapper<Permission> wrapper = new QueryWrapper<>();
        wrapper.orderByDesc("id");
        List<Permission> permissionList = baseMapper.selectList(wrapper);

        List<Permission> result = bulid(permissionList);

        return result;
    }

    //根据角色获取菜单
    @Override
    public List<Permission> selectAllMenu(String roleId) {
        List<Permission> allPermissionList = baseMapper.selectList(new QueryWrapper<Permission>().orderByAsc("CAST(id AS SIGNED)"));

        // （1）根据角色id，获取当前角色的菜单权限（同时，所查询到的数据需要满足 未被逻辑删除;）
        List<RolePermission> rolePermissionList = rolePermissionService.list(
                new QueryWrapper<RolePermission>().eq("role_id",roleId).eq("is_deleted" , 0));
        //转换给角色id与角色权限对应Map对象
//        List<String> permissionIdList = rolePermissionList.stream().map(e -> e.getPermissionId()).collect(Collectors.toList());
//        allPermissionList.forEach(permission -> {
//            if(permissionIdList.contains(permission.getId())) {
//                permission.setSelect(true);
//            } else {
//                permission.setSelect(false);
//            }
//        });
        for (int i = 0; i < allPermissionList.size(); i++) {
            Permission permission = allPermissionList.get(i);
            for (int m = 0; m < rolePermissionList.size(); m++) {
                RolePermission rolePermission = rolePermissionList.get(m);
                if(rolePermission.getPermissionId().equals(permission.getId())) {
                    permission.setSelect(true);
                }
            }
        }


        List<Permission> permissionList = bulid(allPermissionList);
        return permissionList;
    }

    //给角色分配权限
    @Override
    public void saveRolePermissionRealtionShip(String roleId, String[] permissionIds) {

        rolePermissionService.remove(new QueryWrapper<RolePermission>().eq("role_id", roleId));

  

        List<RolePermission> rolePermissionList = new ArrayList<>();
        for(String permissionId : permissionIds) {
            if(StringUtils.isEmpty(permissionId)) continue;
      
            RolePermission rolePermission = new RolePermission();
            rolePermission.setRoleId(roleId);
            rolePermission.setPermissionId(permissionId);
            rolePermissionList.add(rolePermission);
        }
        rolePermissionService.saveBatch(rolePermissionList);
    }

    //递归删除菜单
    @Override
    public void removeChildById(String id) {
        List<String> idList = new ArrayList<>();
        this.selectChildListById(id, idList);

        idList.add(id);
        baseMapper.deleteBatchIds(idList);
    }

    //根据用户id获取用户菜单
    @Override
    public List<String> selectPermissionValueByUserId(String id) {

        List<String> selectPermissionValueList = null;
        if(this.isSysAdmin(id)) {
            //如果是系统管理员，获取所有权限
            selectPermissionValueList = baseMapper.selectAllPermissionValue();
        } else {
            selectPermissionValueList = baseMapper.selectPermissionValueByUserId(id);
        }
        return selectPermissionValueList;
    }

    @Override
    public List<JSONObject> selectPermissionByUserId(String userId) {
        List<Permission> selectPermissionList = null;
        if(this.isSysAdmin(userId)) {
            //如果是超级管理员，获取所有菜单
            selectPermissionList = baseMapper.selectList(null);
        } else {
            selectPermissionList = baseMapper.selectPermissionByUserId(userId);
        }

        List<Permission> permissionList = PermissionHelper.bulid(selectPermissionList);
        List<JSONObject> result = MemuHelper.bulid(permissionList);
        return result;
    }

    /**
     * 判断用户是否系统管理员
     * @param userId
     * @return
     */
    private boolean isSysAdmin(String userId) {
        User user = userService.getById(userId);

        if(null != user && "admin".equals(user.getUsername())) {
            return true;
        }
        return false;
    }

    /**
     *	递归获取子节点
     * @param id
     * @param idList
     */
    private void selectChildListById(String id, List<String> idList) {
        List<Permission> childList = baseMapper.selectList(new QueryWrapper<Permission>().eq("pid", id).select("id"));
        childList.stream().forEach(item -> {
            idList.add(item.getId());
            this.selectChildListById(item.getId(), idList);
        });
    }

    /**
     * 使用递归方法建菜单
     * @param treeNodes
     * @return
     */
    private static List<Permission> bulid(List<Permission> treeNodes) {
        List<Permission> trees = new ArrayList<>();
        for (Permission treeNode : treeNodes) {
            if ("0".equals(treeNode.getPid())) {
                treeNode.setLevel(1);
                trees.add(findChildren(treeNode,treeNodes));
            }
        }
        return trees;
    }

    /**
     * 递归查找子节点
     * @param treeNodes
     * @return
     */
    private static Permission findChildren(Permission treeNode,List<Permission> treeNodes) {
        treeNode.setChildren(new ArrayList<Permission>());

        for (Permission it : treeNodes) {
            if(treeNode.getId().equals(it.getPid())) {
                int level = treeNode.getLevel() + 1;
                it.setLevel(level);
                if (treeNode.getChildren() == null) {
                    treeNode.setChildren(new ArrayList<>());
                }
                treeNode.getChildren().add(findChildren(it,treeNodes));
            }
        }
        return treeNode;
    }


    //========================递归查询所有菜单================================================
    @Override
    public List<Permission> getAllMenu() {
        //（1）查询出菜单的所有记录 && 根据pid值，升序显示;
        QueryWrapper<Permission> queryWrapper = new QueryWrapper<>();
        queryWrapper.orderByDesc("pid");
        List<Permission> permissions = this.list(queryWrapper);

        //（2）创建permission集合，来记录pid = 0下的所有记录（
        List<Permission> allPermissions = new ArrayList<>();

        //（3）遍历所要菜单记录，寻找到pid = 0的菜单记录
        for (Permission permission : permissions) {
            // 首先，选择level = 0的菜单节点作为根节点出发，递归寻找所有符合条件的子节点
            if("0".equals(permission.getPid())){
                // 当前pid = 0的记录，被加入到allPermissions集合中;
                allPermissions.add(permission);
                // 设置当前记录的level;
                permission.setLevel(0);
                //（4）传入某个permission节点，查询其所有子节点记录 && 传入所有permission记录;
                List<Permission> children = getChildren(permission , permissions);
                // 设置当前记录的所有子节点
                permission.setChildren(children);
            }
        }

        return allPermissions;
    }


    // 递归获取当前permission节点的所有子节点
    private List<Permission> getChildren(Permission root, List<Permission> permissions) {
        // 用来记录root对象的所有子节点集合;
        List<Permission> list = new ArrayList<>();
        for (Permission permission : permissions) {
            // （1）遍历所有permission信息，获取permission的pid == root对象id;
            // 即，等价于获取root对象下的子节点集合;
            if(permission.getPid().equals(root.getId())){
                // （2）符合条件的permission对象，加入到root对象的子节点集合中;
                list.add(permission);
                // 设置该permission对象的level属性
                permission.setLevel(root.getLevel() + 1);
                // 递归获取当前permission对象的子节点集合;
                List<Permission> children = getChildren(permission , permissions);
                permission.setChildren(children);
            }
        }
        return list;
    }

    //============递归删除菜单==================================
    @Override
    public void deletePermissions(String id) {
        //（1）创建list集合，用来存储所有需要删除permission对象的id集合;
        List<String> toDeleteList = new ArrayList<>();
        //（2）递归查询当前id对应permission对象下的所有子节点
        getAllChildren(id , toDeleteList);
        //（3）当前permission对象也需要加入到集合中
        toDeleteList.add(id);
        //（4）根据id集合，删除所有permission记录;
        this.removeByIds(toDeleteList);
    }

    // 递归获取root对象下子节点的id值集合;
    private void getAllChildren(String id, List<String> toDeleteList) {
        //（1）封装查询条件 ：pid == id && 需要查询的列为id;
        QueryWrapper<Permission> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("pid" , id);
        queryWrapper.select("id");
        //（2）获取所有符合条件的permission对象;
        List<Permission> list = this.list(queryWrapper);
        //（3）遍历所获取到的所有permission对象集合
        list.stream().forEach(permission -> {
            String permissionId = permission.getId();
            toDeleteList.add(permissionId);
            // 递归获取子节点的id值集合;
            getAllChildren(permissionId , toDeleteList);
        });

    }

    //=========================给角色分配菜单=======================
    @Override
    public void permissionsToRole(String roleId, String[] permissionIds) {
        List<RolePermission> rolePermissions = new ArrayList<>();
        // 向acl-role-permissions表中，添加角色role和菜单权限permission的若干条对应关系;
        for (String permissionId : permissionIds) {
            if(StringUtils.isEmpty(permissionId)){
                continue;
            }
            RolePermission rolePermission = new RolePermission();
            rolePermission.setRoleId(roleId);
            rolePermission.setPermissionId(permissionId);
            rolePermissions.add(rolePermission);
        }
        rolePermissionService.saveBatch(rolePermissions);
    }
}
